#include "NetSession.h"

#include <boost/bind.hpp>
#include <boost/asio/placeholders.hpp>
#include <iostream>

NetSession::NetSession(boost::asio::io_service& service) :
    strand_(service), socket_(service)
{
}

NetSession::~NetSession()
{
}

void NetSession::Start()
{
    addr_ = socket_.remote_endpoint().address().to_string();
    port_ = socket_.remote_endpoint().port();

    std::cout << "open session : " << addr_ << ":" << port_ << "\n";

    socket_.async_read_some(
        boost::asio::buffer(buffer_),
        strand_.wrap(
            boost::bind(
                &NetSession::handle_read, shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        )
    );
}

void NetSession::Close()
{
    std::cout << "close session : " << addr_ << ":" << port_ << "\n";
    boost::system::error_code ignored_ec;
    socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
}

void NetSession::handle_read(const boost::system::error_code& error,
                 size_t bytes_transferred)
{
    if (error) {
        std::cerr << error.message() << "\n";
        Close();
        return;
    }

    if (false == ReadBuffer(&buffer_[0], bytes_transferred)) {
        std::cerr << "ReadBuffer fail" << "\n";
        Close();
        return;
    }

    if (false == ReadPacket()) {
        std::cerr << "ReadPacket fail" << "\n";
        Close();
        return;
    }

    socket_.async_read_some(
        boost::asio::buffer(buffer_),
        strand_.wrap(
            boost::bind(
                &NetSession::handle_read, shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        )
    );
}

void NetSession::handle_write(const boost::system::error_code& error)
{
    if (error) {
        std::cerr << error.message() << "\n";
        Close();
        return;
    }
}

bool NetSession::ReadBuffer(const char* buf, const size_t bufLen)
{
    if(recvBuf_.capacity() < recvBuf_.size() + bufLen) {
        recvBuf_.set_capacity(recvBuf_.size() + bufLen);
    }
    recvBuf_.insert(recvBuf_.end(), buf, buf + bufLen);

    return true;
}

bool NetSession::SendBuffer(const char* buf, const size_t bufLen)
{
    sendBuf_.resize(bufLen);
    std::memcpy(&sendBuf_[0], buf, bufLen);

    boost::asio::async_write(socket_, 
        boost::asio::buffer(sendBuf_.linearize(), sendBuf_.size()),
        strand_.wrap(
            boost::bind(
                &NetSession::handle_write, shared_from_this(),
                boost::asio::placeholders::error
            )
        )
    );

    return true;
}
